﻿/*======================================================================
== Copyright : BlueCurve (c)
== Licence   : Gnu/GPL v2.x
== Author    : Teddy Albina
== Email     : bluecurveteam@gmail.com
== Web site  : http://www.codeplex.com/BlueCurve
========================================================================*/
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using BlueCurve.Common.Application;
using BlueCurve.WcfServices;
using BlueCurveRepository.Remoting;
using System.Data.Linq;

namespace BlueCurveRepository
{
    /// <summary>
    /// Class principale de l'application
    /// </summary>
    class Program : BlueCurve.Common.InteractiveConsole.BaseConsole
    {
        #region 'Configuration'

        /// <summary>
        /// Thread de la console interactive
        /// </summary>
        private static Thread s_console { get; set; }
        /// <summary>
        /// Thread de gestion de la base de données
        /// </summary>
        private static Thread s_checkdb { get; set; }

        #endregion


        
        #region 'Functions'

        /// <summary>
        /// Fonction principal de l'application
        /// </summary>
        static void Main(string[] args)
        {
            s_console = new Thread(new ThreadStart(new Program().Run));
            s_checkdb = new Thread(new ThreadStart(CheckDatabase));
            s_console.Start();
            s_checkdb.Start();

            Tcpservice._RestartApplication += new EventHandler(TcpserviceRestartApplication);
            Tcpservice._StopApplication += new EventHandler(TcpserviceStopApplication);
            Tcpservice.AddFileToCache += new Tcpservice.EventAddFile(Tcpservice_AddFileToCache);
            Tcpservice.AddFileToScheduleCache += new Tcpservice.EventAddFileToSchedule(Tcpservice_AddFileToScheduleCache);
            Tcpservice.AddParsableFileToDatabase += new Tcpservice.EventAddParsableFile(Tcpservice_AddParsableFileToDatabase);
            Tcpservice.DeleteFileFromCache += new Tcpservice.EventDeleteFile(Tcpservice_DeleteFileFromCache);
            Tcpservice.GetFilesToIndex += new Tcpservice.EventGetFileToIndex(Tcpservice_GetFilesToIndex);
            Tcpservice.GetFilesToParse += new Tcpservice.EventGetFileToParse(Tcpservice_GetFilesToParse);
            Tcpservice.GetFilesToSchedule += new Tcpservice.EventGetFileToSchedule(Tcpservice_GetFilesToSchedule);
            Tcpservice.GetNewListFilesToIndex += new Tcpservice.EventGetListFilesToIndex(Tcpservice_GetNewListFilesToIndex);
            Tcpservice.GetNewListFilesToParse += new Tcpservice.EventGetListFilesToParse(Tcpservice_GetNewListFilesToParse);

            // Demarrage du service wcf
            Host.StartService<Tcpservice>();
        }

        /// <summary>
        /// Déplace les fichiers vers IndexerCache
        /// </summary>
        private static void CheckDatabase()
        {
            while (true)
            {
                using (RepositorydbDataContext db = new RepositorydbDataContext())
                {
                    db.BackFileToIndexerCache();
                }
                Thread.Sleep(10 * 60 * 1000);
            }
        }

        /// <summary>
        /// Obtiens une liste de fichiers à parser
        /// </summary>
        /// <returns>Liste de chemins de fichiers</returns>
        private static List<string> Tcpservice_GetNewListFilesToParse(object sender, Tcpservice.EventData e)
        {
            using (RepositorydbDataContext db = new RepositorydbDataContext())
            {
                return db.CrawlingApplicationCache.Where(p => p.ATTRIB.Equals(false))
                                                  .Select(o => o.PATH)
                                                  .Take(e.max).ToList();
            }
        }

        /// <summary>
        /// Obtiens une liste de fichiers à indexer
        /// </summary>
        /// <returns>Liste de chemins de fichiers</returns>
        private static List<string> Tcpservice_GetNewListFilesToIndex(object sender, Tcpservice.EventData e)
        {
            using (RepositorydbDataContext db = new RepositorydbDataContext())
            {
                return db.IndexerCache.Where(p => p.ATTRIB.Equals(false))
                                      .Select(o => o.PATH)
                                      .Take(e.max).ToList();
            }
        }

        /// <summary>
        /// Obtiens un fichier pour le scheduler
        /// </summary>
        /// <returns>Chemin du fichier</returns>
        private static string Tcpservice_GetFilesToSchedule(object sender, EventArgs e)
        {
            try
            {
                string path = null;
                using (RepositorydbDataContext db = new RepositorydbDataContext())
                {
                    path = db.SchedulerCache.Select(p => p.PATH)
                                            .Take(1)
                                            .Single();

                    if (!string.IsNullOrEmpty(path))
                        db.DeleteFile(path);
                }
                
                return path;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// Obtiens un fichier à parser
        /// </summary>
        /// <returns>Chemin du fichier</returns>
        private static string Tcpservice_GetFilesToParse(object sender, EventArgs e)
        {
            try
            {
                string path = null;
                using (RepositorydbDataContext db = new RepositorydbDataContext())
                {
                    path = db.CrawlingApplicationCache.Where(p => p.ATTRIB.Equals(false))
                                                      .Select(o => o.PATH)
                                                      .Take(1)
                                                      .Single();

                    if (!string.IsNullOrEmpty(path))
                    {
                        CrawlingApplicationCache cache = db.CrawlingApplicationCache.Single(p => p.PATH == path);
                        cache.ATTRIB = true;

                        db.SubmitChanges(ConflictMode.FailOnFirstConflict);
                    }
                }

                return path;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// Obtiens un fichier à indexer
        /// </summary>
        /// <returns>Chemin du fichier</returns>
        private static string Tcpservice_GetFilesToIndex(object sender, EventArgs e)
        {
            string path = null;
            using (RepositorydbDataContext db = new RepositorydbDataContext())
            {
                path = db.GetFileToIndex();
                if (!string.IsNullOrEmpty(path))
                    db.UpdateFileAttributionInIndexerCache(path);
            }
            return path;
        }

        /// <summary>
        /// Suppprime un fichier du cache
        /// </summary>
        private static void Tcpservice_DeleteFileFromCache(object sender, Tcpservice.EventData e)
        {
            using (RepositorydbDataContext db = new RepositorydbDataContext())
            {
                db.DeleteFile(e.path);
            }
        }

        /// <summary>
        /// Ajoute un nouveau type de fichier a parser
        /// </summary>
        private static void Tcpservice_AddParsableFileToDatabase(object sender, Tcpservice.EventData e)
        {
            using (RepositorydbDataContext db = new RepositorydbDataContext())
            {
                db.AddParsableFile(e.typeoffile);
            }
        }

        /// <summary>
        /// Ajoute un fichier dans le cache pour les scheduler
        /// </summary>
        private static void Tcpservice_AddFileToScheduleCache(object sender, Tcpservice.EventData e)
        {
            using (RepositorydbDataContext db = new RepositorydbDataContext())
            {
                db.AddFileToSchedule(e.path);
            }
        }

        /// <summary>
        /// Ajoute un fichier dans le cache
        /// </summary>
        private static void Tcpservice_AddFileToCache(object sender, Tcpservice.EventData e)
        {
            using (RepositorydbDataContext db = new RepositorydbDataContext())
            {
                db.AddDataToCache(e.typeoffile, e.path);
            }
        }

        /// <summary>
        /// Arrete l'application
        /// </summary>
        private static void TcpserviceStopApplication(object sender, EventArgs e)
        {
            if (s_checkdb.ThreadState == System.Threading.ThreadState.Running)
                s_checkdb.Abort();

            // Fermeture du service wcf
            Host.StopService();
            // Suicide de l'application
            Process.GetCurrentProcess().Kill();
        }

        /// <summary>
        /// Relance l'application
        /// </summary>
        private static void TcpserviceRestartApplication(object sender, EventArgs e)
        {
            if (s_checkdb.ThreadState == System.Threading.ThreadState.Running)
                s_checkdb.Abort();

            // Enregistre l'application pour le redemarrage
            Restart.RestartApplication(string.Concat(System.Diagnostics.Process.GetCurrentProcess().ProcessName, ".exe"));
            // Fermeture du service wcf
            Host.StopService();
            // Suicide de l'application
            Process.GetCurrentProcess().Kill();
        }

        #endregion

        

        #region 'Console'

        /// <summary>
        /// Chargement des commandes de la console interactive
        /// </summary>
        protected override void LoadCommands()
        {
            this.Commands.Add("-stop", new Dictionary<Action, string>()
            {
                { () => TcpserviceStopApplication(null, EventArgs.Empty), "Permet l'arret de l'application" }
            });
            this.Commands.Add("-restart", new Dictionary<Action, string>()
            {
                { () => TcpserviceRestartApplication(null, EventArgs.Empty), "Permet de relancer l'application" }
            });
        }

        /// <summary>
        /// Nom de l'application
        /// </summary>
        public override string Name
        {
            get { return "BlueCurve Repository"; }
        }

        #endregion
    }
}